﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Polaris.Common;
using Polaris.Domain.Interfaces.Admin;
using Polaris.Domain.Model.DbEntity;
using Polaris.Domain.Model.Dto.Article.Request;
using Polaris.Domain.Model.Dto.Article.Response;
using Polaris.Domain.Model.Entity.Base;
using Polaris.Domain.Model.Entity.Exception;
using Polaris.Domain.Repository.Interfaces;
using Polaris.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;

namespace Polaris.Infrastructure.DomainService.Admin
{
    public class ArticleService : IArticle
    {
        private readonly IBaseRepository<ArticleInfo> _articleInfo;
        private readonly IBaseRepository<ArticleDictionaryRelation> _articleDictionaryRelation;
        private readonly IBaseRepository<ArticleContent> _articleContent;
        private readonly PolarisDbContext _dbContext;

        public ArticleService(IBaseRepository<ArticleInfo> articleInfo, IBaseRepository<ArticleDictionaryRelation> articleDictionaryRelation, IBaseRepository<ArticleContent> articleContent, PolarisDbContext dbContext)
        {
            _articleInfo = articleInfo;
            _articleDictionaryRelation = articleDictionaryRelation;
            _articleContent = articleContent;
            _dbContext = dbContext;
        }

        /// <summary>
        /// 创建文章
        /// </summary>
        /// <param name="create"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task CreateArticle(CreateArticleInfoRequest create, Guid? userId)
        {
            try
            {
                var id = Guid.NewGuid();
                var article = new ArticleInfo()
                {
                    Id = id,
                    Browse = 0,
                    CreateBy = userId,
                    CreateTime = DateTime.Now,
                    Enable = create.Enable,
                    IsComments = create.IsComments,
                    IsDelete = false,
                    IsOriginal = create.IsOriginal,
                    IsPrivacy = create.IsPrivacy,
                    IsRedFlag = create.IsRedFlag,
                    IsTop = create.IsTop,
                    Like = 0,
                    Password = create.IsPrivacy ? create.Password : null,
                    PrimitiveLink = create.IsOriginal ? create.PrimitiveLink : null,
                    PublishTime = create.PublishTime,
                    Title = create.Title,
                    ArticleType = Guid.Parse(create.ArticleType),
                };
                var articleTags = new List<ArticleDictionaryRelation>();
                create.ArticleTag.ForEach(d =>
                {
                    articleTags.Add(new ArticleDictionaryRelation()
                    {
                        ArticleId = id,
                        Id = Guid.NewGuid(),
                        CreateBy = userId,
                        CreatedTime = DateTime.Now,
                        DictionaryId = Guid.Parse(d)
                    });
                });

                var articleContent = new ArticleContent()
                {
                    ArticleId = id,
                    Content = create.Content,
                    CreateBy = userId,
                    CreateTime = DateTime.Now,
                    Id = Guid.NewGuid()
                };

                await _articleContent.AddEntityAsync(articleContent);
                await _articleInfo.AddEntityAsync(article);
                await _articleDictionaryRelation.AddRangeAsync(articleTags);

                await _articleInfo.CommitAsync();
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }

        /// <summary>
        /// 修改文章信息
        /// </summary>
        /// <param name="update"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task UpdateArticle(UpdateArticleInfoRequest update, Guid? userId)
        {
            try
            {
                var article = await _articleInfo.QueryAll(d => d.Id.ToString() == update.Id).FirstAsync();
                article.UpdateBy = userId;
                article.UpdateTime = DateTime.Now;
                article.Enable = update.Enable;
                article.IsComments = update.IsComments;
                article.IsOriginal = update.IsOriginal;
                article.IsPrivacy = update.IsPrivacy;
                article.IsRedFlag = update.IsRedFlag;
                article.IsTop = update.IsTop;
                article.Password = update.Password;
                article.PrimitiveLink = update.PrimitiveLink;
                article.PublishTime = update.PublishTime;
                article.Title = update.Title;
                article.ArticleType = Guid.Parse(update.ArticleType);

                var articleTags = await _articleDictionaryRelation.QueryAll(d => d.ArticleId == article.Id).ToListAsync();
                var delTags = articleTags.Where(d => update.ArticleTag.Contains(d.DictionaryId.ToString())).ToList();
                var tagIds = articleTags.Where(d => !update.ArticleTag.Contains(d.DictionaryId.ToString())).Select(d => d.DictionaryId.ToString()).ToList();

                articleTags = new List<ArticleDictionaryRelation>();
                update.ArticleTag.Where(d => !tagIds.Contains(d)).ToList().ForEach(d =>
                {
                    articleTags.Add(new ArticleDictionaryRelation()
                    {
                        ArticleId = article.Id,
                        Id = Guid.NewGuid(),
                        CreateBy = userId,
                        CreatedTime = DateTime.Now,
                        DictionaryId = Guid.Parse(d)
                    });
                });
                if (delTags.Any())
                {
                    _articleDictionaryRelation.DeleteRange(delTags);
                }
                if (articleTags.Any())
                {
                    await _articleDictionaryRelation.AddRangeAsync(articleTags);
                }

                var articleContent = await _articleContent.QueryAll(d => d.ArticleId == article.Id).FirstAsync();
                if (articleContent.Content != update.Content)
                {
                    articleContent.UpdateBy = userId;
                    articleContent.Content = update.Content;
                    articleContent.LastUpdateTime = DateTime.Now;
                    _articleContent.UpdateEntity(articleContent);
                }

                _articleInfo.UpdateEntity(article);

                await _articleDictionaryRelation.CommitAsync();
                await _articleInfo.CommitAsync();
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }

        }

        /// <summary>
        /// 根据id获取文章预览内容
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<PreviewArticleResponse> GetArticleContentById(string id)
        {
            var linqStr = _dbContext.ArticleContent
                .Where(a => a.ArticleId.ToString() == id)
                .Join(
                    _dbContext.ArticleInfo,
                    ac => ac.ArticleId,
                    a => a.Id,
                    (ac, a) => new PreviewArticleResponse
                    {
                        Content = ac.Content,
                        Title = a.Title,
                    }
                );
            var result = await linqStr.FirstOrDefaultAsync();
            return result;
        }

        /// <summary>
        /// 根据id获取文章
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<UpdateArticleInfoRequest> GetArticleInfoById(string id)
        {
            try
            {
                var linqStr = from a in _dbContext.ArticleInfo
                              join ac in _dbContext.ArticleContent on a.Id equals ac.ArticleId
                              join tMap in _dbContext.ArticleDictionaryRelation on a.Id equals tMap.ArticleId
                              join tag in _dbContext.Sys_Dictionary_Item on tMap.DictionaryId equals tag.Id
                              join type in _dbContext.Sys_Dictionary_Item on a.ArticleType equals type.Id
                              where a.Id.ToString() == id
                              //select a;
                              group tag.Id by new
                              {
                                  a.Title,
                                  a.IsComments,
                                  a.IsOriginal,
                                  a.IsPrivacy,
                                  a.IsRedFlag,
                                  a.IsTop,
                                  a.Password,
                                  a.PrimitiveLink,
                                  ac.Content,
                                  a.Enable,
                                  a.PublishTime,
                                  typeId = type.Id,
                                  aId = a.Id
                              } into aGroup
                              select new UpdateArticleInfoRequest
                              {
                                  Id = aGroup.Key.aId.ToString(),
                                  Title = aGroup.Key.Title,
                                  ArticleType = aGroup.Key.typeId.ToString(),
                                  Content = aGroup.Key.Content,
                                  Enable = aGroup.Key.Enable,
                                  IsComments = aGroup.Key.IsComments,
                                  IsOriginal = aGroup.Key.IsOriginal,
                                  IsPrivacy = aGroup.Key.IsPrivacy,
                                  IsRedFlag = aGroup.Key.IsRedFlag,
                                  IsTop = aGroup.Key.IsTop,
                                  Password = aGroup.Key.Password,
                                  PrimitiveLink = aGroup.Key.PrimitiveLink,
                                  PublishTime = aGroup.Key.PublishTime,
                                  ArticleTag = aGroup.Select(d => d.ToString()).ToList()
                              };
                var result = await linqStr.FirstOrDefaultAsync();
                return result;
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }

        }

        /// <summary>
        /// 获取文章列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        /// <exception cref="CustomException"></exception>
        public async Task<PaginationInfo<ArticleListInfoResponse>> GetArticleList(ArticleQueryRequest query)
        {
            try
            {
                Expression<Func<ArticleInfo, bool>> exp = e => e.IsDelete == false;
                exp = exp.And(e => !e.IsDelete);

                var linqStr = _dbContext.ArticleInfo
                     .Where(exp)
                     .Join(
                         _dbContext.ArticleDictionaryRelation,
                         a => a.Id,
                         at => at.ArticleId,
                         (a, at) => new
                         {
                             articleInfo = a,
                             relation = at
                         }
                     )
                     .Join(
                         _dbContext.Sys_Dictionary_Item,
                         com => com.relation.DictionaryId,
                         item => item.Id,
                         (com, item) => new
                         {
                             articleInfo = com.articleInfo,
                             relation = com.relation,
                             tagItem = item
                         }
                     )
                     .Join(
                         _dbContext.Sys_Dictionary_Item,
                         com => com.articleInfo.ArticleType, // 文章类型
                         item => item.Id,
                         (com, typeItem) => new
                         {
                             articleInfo = com.articleInfo,
                             tagItem = com.tagItem,
                             typeItem = typeItem // 文章类型
                         }
                     )
                     .OrderByDescending(d => d.articleInfo.CreateTime)
                     .GroupBy(
                         result => new
                         {
                             result.articleInfo.Id,
                             result.articleInfo.Title,
                             result.articleInfo.IsRedFlag,
                             result.articleInfo.IsTop,
                             result.articleInfo.Browse,
                             result.articleInfo.Enable,
                             result.articleInfo.IsComments,
                             result.articleInfo.IsPrivacy,
                             result.articleInfo.Like,
                         },
                         (key, g) => new ArticleListInfoResponse()
                         {
                             Id = key.Id.ToString(),
                             Title = key.Title,
                             IsRedFlag = key.IsRedFlag,
                             IsTop = key.IsTop,
                             Browse = key.Browse,
                             Enable = key.Enable,
                             IsComments = key.IsComments,
                             IsPrivacy = key.IsPrivacy,
                             Like = key.Like,
                             Type = g.Select(x => x.typeItem.Name).FirstOrDefault(), // 获取文章类型
                             Tags = g.Select(x => x.tagItem.Name).ToList(), // 获取标签列表

                         }
                     ).Skip((query.PageIndex - 1) * query.PageSize).Take(query.PageSize);

                var result = await linqStr.ToListAsync();
                var total = await _articleInfo.GetEntitiesCountAsync(exp);
                return ApiResult.CreatePaginationInfo(
                                                        PageIndex: query.PageIndex,
                                                        PageSize: query.PageSize,
                                                        Total: total,
                                                        Result: result
                                                     );
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }

        /// <summary>
        /// 删除文章根据id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteArticleById(string id, Guid? userId)
        {
            try
            {
                var article = await _articleInfo.QueryAll(d => d.Id.ToString() == id).FirstOrDefaultAsync();
                if (article == null)
                {
                    throw new CustomException(Domain.Model.Enum.ResultCode.NO_DATA, "数据未找到");
                }
                article.IsDelete = true;
                article.UpdateBy = userId;
                article.UpdateTime = DateTime.Now;
                await _articleInfo.CommitAsync();
            }
            catch (Exception ex)
            {
                throw new CustomException(Domain.Model.Enum.ResultCode.FAIL, ex.Message);
            }
        }
    }
}
